#include "streamrecorder-MarsCode-AI.h"
#include <QDir>
#include <QFileInfo>
#include <QRegularExpression>
#include <QSettings>

StreamRecorder::StreamRecorder(const Config& config, QObject* parent)
    : QObject(parent), m_config(config)
{
    m_maxRetries = m_config.maxRetries;
    m_retryInterval = m_config.retryInterval;

    // 确保分段文件保存路径存在
    QDir segmentDir(m_config.segmentPath);
    if (!segmentDir.exists()) {
        segmentDir.mkpath(".");
    }

    initFFmpegProcess();
    initQoSTimers();
    setupHardwareAcceleration();
}

StreamRecorder::~StreamRecorder()
{
    stopFFmpegGracefully();
    if (m_qosTimer) {
        m_qosTimer.reset();
    }
    if (m_process) {
        m_process.reset();
    }
}

void StreamRecorder::start()
{
    if (m_active.test_and_set())
        throw std::runtime_error("Converter already running");

    m_currentRetry = 0;
    m_processedFrames = 0;
    startConversion();
}

void StreamRecorder::stop()
{
    stopFFmpegGracefully();
}

void StreamRecorder::adjustEncodingParams(const QStringList& newParams)
{
    QMutexLocker lock(&m_paramMutex);
    m_currentParams = newParams;
    m_needsRestart = true;
    restartIfNeeded();
}

void StreamRecorder::initFFmpegProcess()
{
    m_process.reset(new QProcess);
    m_process->setProcessChannelMode(QProcess::MergedChannels);
    connect(m_process.get(), &QProcess::readyReadStandardError, this, &StreamRecorder::parseOutput);
    connect(m_process.get(), QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,
            &StreamRecorder::handleProcessExit);
}

void StreamRecorder::initQoSTimers()
{
    m_qosTimer.reset(new QTimer);
    m_qosTimer->setInterval(2000);
    connect(m_qosTimer.get(), &QTimer::timeout, this, [this] {
        calculateQoSMetrics();
        adjustBandwidth();
    });
}

void StreamRecorder::setupHardwareAcceleration()
{
    if (m_config.hwAccel) {
#if defined(Q_OS_WIN)
        m_config.customArgs.prepend("-hwaccel");
        m_config.customArgs.prepend("dxva2");
#elif defined(Q_OS_LINUX)
        m_config.customArgs.prepend("-hwaccel");
        m_config.customArgs.prepend("vaapi");
#elif defined(Q_OS_MACOS)
        m_config.customArgs.prepend("-hwaccel");
        m_config.customArgs.prepend("videotoolbox");
#endif
    }
}

void StreamRecorder::startConversion()
{
    startConversionFromFrame(0);
}

void StreamRecorder::parseOutput()
{
    static QByteArray buffer;
    buffer += m_process->readAllStandardError();

    while (buffer.contains('\n')) {
        int pos = buffer.indexOf('\n');
        QByteArray line = buffer.left(pos).trimmed();
        buffer = buffer.mid(pos + 1);

        processLine(line);
    }
}

void StreamRecorder::processLine(const QByteArray& line)
{
    // 进度解析
    if (line.startsWith("frame=")) {
        QRegularExpression re(R"(frame=\s*(\d+))");
        QRegularExpressionMatch match = re.match(line);
        if (match.hasMatch()) {
            m_processedFrames = match.captured(1).toInt();
        }

        re.setPattern(R"(time=(\d+):(\d{2}):(\d{2})\.(\d{2}))");
        match = re.match(line);
        if (match.hasMatch()) {
            qint64 ms = match.captured(1).toInt() * 3600000 + match.captured(2).toInt() * 60000
                    + match.captured(3).toInt() * 1000 + match.captured(4).toInt() * 10;
            if (m_totalDuration > 0) {
                emit progressUpdated(static_cast<double>(ms) / m_totalDuration,
                                     m_startTime.msecsTo(QDateTime::currentDateTime()));
            }
        }
    }

    // QoS指标提取
    if (line.contains("fps=")) {
        QRegularExpression re(R"(fps=\s*(\d+))");
        QRegularExpressionMatch match = re.match(line);
        if (match.hasMatch()) {
            m_currentFps = match.captured(1).toDouble();
        }
    }

    if (line.contains("bitrate=")) {
        QRegularExpression re(R"(bitrate=\s*([\d.]+)\s*kb/s)");
        QRegularExpressionMatch match = re.match(line);
        if (match.hasMatch()) {
            m_currentBitrate = match.captured(1).toDouble();
        }
    }

    // 错误检测
    if (line.contains("Connection timed out")) {
        qDebug() << "Network connection timed out, handling error...";
        handleNetworkError();
    }
}

void StreamRecorder::calculateQoSMetrics()
{
    // 计算帧率稳定性
    m_fpsHistory.append(m_currentFps);
    if (m_fpsHistory.size() > 5)
        m_fpsHistory.removeFirst();

    // 计算码率波动
    m_bitrateHistory.append(m_currentBitrate);
    if (m_bitrateHistory.size() > 5)
        m_bitrateHistory.removeFirst();

    // 发送QoS信号
    emit qosMetrics(calculateAverage(m_fpsHistory), calculateAverage(m_bitrateHistory));
}

void StreamRecorder::adjustBandwidth()
{
    const double current = calculateAverage(m_bitrateHistory);
    if (current > m_config.maxBandwidth * 1.1) {
        int newBitrate = m_config.maxBandwidth * 0.9;
        updateBitrateParams(newBitrate);
        emit bandwidthAdjusted(newBitrate);
    }
}

void StreamRecorder::updateBitrateParams(int newBitrate)
{
    QMutexLocker lock(&m_paramMutex);
    m_currentParams.removeAll("-b:v");
    m_currentParams << "-b:v" << QString::number(newBitrate) + "k";
    m_needsRestart = true;
    restartIfNeeded();
}

void StreamRecorder::restartIfNeeded()
{
    if (m_needsRestart && !m_restartTimer && m_currentRetry < m_maxRetries) {
        m_restartTimer = std::make_unique<QTimer>();
        m_restartTimer->setSingleShot(true);
        int retryDelay = m_retryInterval * (1 << m_currentRetry); // 指数退避
        connect(m_restartTimer.get(), &QTimer::timeout, this, [this] {
            stopFFmpegGracefully();
            startConversionFromFrame(m_lastProcessedFrame);
            m_needsRestart = false;
            m_restartTimer.reset();
            m_currentRetry++;
        });
        m_restartTimer->start(retryDelay);
    } else if (m_currentRetry >= m_maxRetries) {
        emit errorOccurred(tr("Max retries reached, unable to restart FFmpeg."));
    }
}

void StreamRecorder::handleNetworkError()
{
    if (++m_networkErrors < 3) {
        qDebug() << "Network error detected, attempting quick recover...";
        quickRecover();
    } else {
        qDebug() << "Persistent network errors, scheduling retry...";
        scheduleRetry();
    }
}

void StreamRecorder::quickRecover()
{
    sendFFmpegCommand("reconnect");
    sendFFmpegCommand("clear");
    QTimer::singleShot(1000, this, [this] {
        if (m_process && !m_process->isReadable()) {
            if (m_process) {
                m_process->terminate();
                m_process->waitForFinished();
            }
            startConversion();
        }
    });
}

void StreamRecorder::sendFFmpegCommand(const QString& cmd)
{
    if (m_process && m_process->state() == QProcess::Running) {
        m_process->write(cmd.toUtf8() + "\n");
    }
}

void StreamRecorder::reconnectStream()
{
    if (m_process) {
        m_process->write("q"); // 发送FFmpeg的退出命令
        m_process->waitForFinished(1000);
    }
    startConversion();
}

void StreamRecorder::validateOutput()
{
    QFileInfo fi(m_config.outputFile);
    static qint64 lastSize = 0;

    // 检查文件增长
    if (fi.size() == lastSize && fi.size() > 0) {
        qDebug() << "Output file not growing, scheduling retry...";
        emit outputValidated(false);
        emit errorOccurred(tr("Output file not growing"));
        scheduleRetry();
    }
    lastSize = fi.size();

    // 检查文件可读性（示例）
    QFile file(m_config.outputFile);
    if (file.open(QIODevice::ReadOnly)) {
        file.seek(file.size() - 256);
        if (file.read(256).contains("moov")) { // MP4文件尾验证
            emit outputValidated(true);
        }
        file.close();
    }
}

void StreamRecorder::scheduleRetry()
{
    if (++m_currentRetry <= m_maxRetries) {
        qWarning() << "Scheduling retry" << m_currentRetry << "/" << m_maxRetries << "in"
                   << m_retryInterval << "ms";
        if (m_process) {
            m_process->terminate();
            m_process->waitForFinished();
        }
        QTimer::singleShot(m_retryInterval, this, [this] {
            if (m_process) {
                m_process->deleteLater(); // 清理旧进程
            }
            initFFmpegProcess(); // 重新初始化
            startConversion();
        });
    } else {
        qCritical() << "Max retries reached";
        emit errorOccurred(tr("Max retries reached"));
    }
}

double StreamRecorder::calculateAverage(const QList<double>& list)
{
    if (list.isEmpty())
        return 0;
    double sum = 0;
    for (double value : list) {
        sum += value;
    }
    return sum / list.size();
}

void StreamRecorder::cleanup()
{
    m_active.clear();
    if (m_qosTimer) {
        m_qosTimer->stop();
    }
    if (m_restartTimer) {
        m_restartTimer->stop();
    }
    m_networkErrors = 0;
    m_needsRestart = false;
    emit statusMessage(tr("Conversion stopped"));
}

void StreamRecorder::startConversionFromFrame(qint64 frame)
{
    QMutexLocker lock(&m_paramMutex);

    // 生成新的分段文件名
    m_currentSegment++;
    QString fileExtension = m_config.outputFile.section('.', -1);
    QString segmentFileName = QString("%1/segment_%2.%3")
                                      .arg(m_config.segmentPath)
                                      .arg(m_currentSegment)
                                      .arg(fileExtension);
    m_config.outputFile = segmentFileName;

    QStringList args = { "-y",         "-i",      m_config.inputUrl, "-movflags",
                         "+faststart", "-strict", "experimental" };

    if (frame > 0) {
        args << "-ss" << QString::number(frame / m_currentFps); // 从指定帧开始
    }

    // 添加分段参数
    args << "-f" << "segment";
    args << "-segment_time" << "00:01:00"; // 每段时长为1分钟，可根据需要调整
    args << "-reset_timestamps" << "1";
    args << "-strftime" << "1";
    args << "-segment_format_options" << "movflags=+faststart"; // 添加该选项
    args << QString("%1/segment_%%Y%%m%%d%%H%%M%%S.%2")
                    .arg(m_config.segmentPath)
                    .arg(fileExtension);

    args += m_config.customArgs;
    args += m_currentParams;

    m_process->start("ffmpeg", args);
    m_startTime = QDateTime::currentDateTime();
    m_qosTimer->start();
    emit statusMessage(
            tr("Conversion started for segment %1 from frame %2").arg(m_currentSegment).arg(frame));
}

void StreamRecorder::stopFFmpegGracefully()
{
    qDebug() << "Attempting to stop FFmpeg gracefully...";
    if (m_process->state() == QProcess::Running) {
        m_lastProcessedFrame = m_processedFrames;
        m_process->write("q");
        if (!m_process->waitForFinished(5000)) {
            m_process->kill();
            m_process->waitForFinished();
            qDebug() << "FFmpeg failed to exit gracefully, forced termination.";
            emit errorOccurred(tr("FFmpeg failed to exit gracefully, forced termination."));
        } else {
            qDebug() << "FFmpeg stopped gracefully.";
        }
    }
}